#include "driver/adc.h"
#include "driver/gpio.h"
#include "esp_adc_cal.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdio.h>
#include <stdlib.h>

#define TAG "BAT ADC"
#define DEFAULT_VREF 1100 // 默认 Vref 为 1100mV
#define NO_OF_SAMPLES 64  // 多重采样次数

static esp_adc_cal_characteristics_t *adc_chars;
#define GPIO_INPUT_IO_4 4                            // GPIO4 (ADC2 Channel 0)
static const adc_channel_t channel = ADC2_CHANNEL_0; // ADC2 channel for GPIO4
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_2; // ADC2

// voltage to raw data struct
typedef struct {
    float vol;
    uint32_t raw;
} vol_to_raw_t;

/* 设置电压阈值，约为 2.00V - 3.30V */
#define VAL_TO_RAW_NUM 14
static const vol_to_raw_t g_v0l_to_raw[VAL_TO_RAW_NUM] = {
    {2.00, 3123}, {2.10, 3207}, {2.20, 3301}, {2.27, 3361}, {2.35, 3434}, {2.43, 3515}, {2.52, 3598},
    {2.60, 3682}, {2.68, 3745}, {2.76, 3825}, {2.80, 3867}, {2.90, 3891}, {3.00, 3986}, {3.30, 4095},
};

// 将原始 ADC 值转换为电压
static float ulp_adc_raw_to_vol(uint32_t adc_raw) {
    if (adc_raw < g_v0l_to_raw[0].raw || adc_raw > g_v0l_to_raw[VAL_TO_RAW_NUM - 1].raw) {
        return 0;
    }

    float ret_vol = 0;
    for (int i = 0; i < VAL_TO_RAW_NUM - 1; i++) {
        if (g_v0l_to_raw[i].raw <= adc_raw && g_v0l_to_raw[i + 1].raw >= adc_raw) {
            uint32_t raw_dif = g_v0l_to_raw[i + 1].raw - g_v0l_to_raw[i].raw;
            float vol_dif = g_v0l_to_raw[i + 1].vol - g_v0l_to_raw[i].vol;
            ret_vol = g_v0l_to_raw[i].vol + (float)(adc_raw - g_v0l_to_raw[i].raw) / (float)raw_dif * vol_dif;
            break;
        }
    }
    return ret_vol;
}

void bat_driver_init() {
    // 检查是否支持 eFuse Two Point 和 Vref
    if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
        ESP_LOGI(TAG, "eFuse Two Point: Supported\n");
    } else {
        ESP_LOGI(TAG, "eFuse Two Point: NOT supported\n");
    }

    if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
        ESP_LOGI(TAG, "eFuse Vref: Supported\n");
    } else {
        ESP_LOGI(TAG, "eFuse Vref: NOT supported\n");
    }

    // 配置 ADC2
    adc2_config_channel_atten(channel, atten);

    // 配置 ADC 校准
    adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
    esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars);

    if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
        ESP_LOGI(TAG, "Characterized using Two Point Value\n");
    } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
        ESP_LOGI(TAG, "Characterized using eFuse Vref\n");
    } else {
        ESP_LOGI(TAG, "Characterized using Default Vref\n");
    }
}

int get_battery_percent() {
    int adc_reading = 0;
    // 多重采样
    for (int i = 0; i < NO_OF_SAMPLES; i++) {
        int raw;
        adc2_get_raw(channel, width, &raw);
        adc_reading += raw;
    }
    adc_reading /= NO_OF_SAMPLES; // 取多重采样的平均值
    // 将原始 ADC 值转换为电压（mV）
    int voltage = 0;
    if (adc_reading < 3123) { // 如果电压小于 2.00V (3123)
        voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
    } else {
        float voltage_f = ulp_adc_raw_to_vol(adc_reading) * 1000;
        voltage = (int)voltage_f;
    }
    ESP_LOGI(TAG, "Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);

    return 0;
}
